﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using log4net;
using TeamCommunitySolution.Modules.Leagues.Requests;
using TeamCommunitySolution.Modules.Leagues.Responses;
using TeamCommunitySolution.Repositories.Base;
using TeamCommunitySolution.Repositories.Leagues;
using TeamCommunitySolution.Domain.DataLayer.Leagues;
using TeamCommunitySolution.Modules.Shared;

namespace TeamCommunitySolution.Modules.Leagues
{
    /// <summary>
    /// The Lague manager implementation.
    /// </summary>
    public class LeagueManagerImpl : LeagueManager
    {
        /// <summary>
        /// Logger instance.
        /// </summary>
        private static readonly ILog _log = LogManager.GetLogger(typeof(LeagueManagerImpl));

        /// <summary>
        /// Base Repository reference.
        /// </summary>
        private LeagueRepository leagueRepo;

        /// <summary>
        /// Prevents a default instance of the <see cref="LeagueManagerImpl"/> class from being created. 
        /// Initializes a new instance of the <see cref="LeagueManagerImpl"/> class.
        /// </summary>
        private LeagueManagerImpl()
        {
        }

        /// <summary>
        /// Creates the instance.
        /// </summary>
        /// <param name="leagueRepo">The league repo.</param>
        /// <returns>Instance of a league manager.</returns>
        public static LeagueManager CreateInstance(LeagueRepository leagueRepo)
        {
            LeagueManagerImpl output = new LeagueManagerImpl();
            output.leagueRepo = leagueRepo;

            return output;
        }

        /// <summary>
        /// Creates the league.
        /// </summary>
        /// <param name="leagueRequest">The league request.</param>
        /// <returns>Creates an instance of a league.</returns>
        public LeagueResponse CreateLeague(LeagueRequest leagueRequest)
        {
            this.ValidateLeagueRequest(leagueRequest);

            LeagueResponse response;
            response = new LeagueResponse();

            try
            {
                League league = new League
                                    {
                                        IsComplete = false,
                                        Name = leagueRequest.LeagueName,
                                        Owner = leagueRequest.Owner,
                                        TeamSize = leagueRequest.TeamSize
                };

                this.leagueRepo.SaveLeague(league);

                response.League = league;
                response.Status = OperationStatus.Success;
            }
            catch (BaseRepositoryException e)
            {
                response.Status = OperationStatus.Failure;
                response.Message = string.Format("Incomplete league creation for request {0} : {1}", leagueRequest.TeamSize, e.Message);
                response.Exception = e;
                _log.Error(response.Message, e);
            }

            return response;
        }

        /// <summary>
        /// Updates the league.
        /// </summary>
        /// <param name="leagueRequest">The league request.</param>
        /// <returns>A response for the operation.</returns>
        public LeagueResponse UpdateLeague(LeagueRequest leagueRequest)
        {
            this.ValidateLeagueRequest(leagueRequest);

            LeagueResponse response;
            response = new LeagueResponse();

            try
            {
                League league = this.GetLeague(leagueRequest).League;
                league.IsComplete = leagueRequest.IsComplete;
                league.Name = leagueRequest.LeagueName;
                league.Owner = leagueRequest.Owner;
                league.TeamSize = leagueRequest.TeamSize;

                this.leagueRepo.SaveLeague(league);

                response.League = league;
                response.Status = OperationStatus.Success;
            }
            catch (LeagueRepositoryException e)
            {
                response.Status = OperationStatus.Failure;
                response.Message = string.Format("Incomplete league update for request {0} : {1}", leagueRequest.TeamSize, e.Message);
                response.Exception = e;
                _log.Error(response.Message, e);
            }

            return response;
        }

        /// <summary>
        /// Gets the league.
        /// </summary>
        /// <param name="leagueRequest">The league request.</param>
        /// <returns>A league response.</returns>
        public LeagueResponse GetLeague(LeagueRequest leagueRequest)
        {
            LeagueResponse response;
            response = new LeagueResponse();

            try
            {
                League league = this.leagueRepo.GetLeagueByField("Id", leagueRequest.Id);
                response.League = league;
            }
            catch (LeagueRepositoryException e)
            {
                response.Status = OperationStatus.Failure;
                response.Message = string.Format("Could not find league for request {0} : {1}", leagueRequest.Id, e.Message);
                response.Exception = e;
                _log.Error(response.Message, e);
            }

            return response;
        }

        /// <summary>
        /// Validates the league request.
        /// </summary>
        /// <param name="leagueRequest">The league request.</param>
        private void ValidateLeagueRequest(LeagueRequest leagueRequest)
        {
            if (leagueRequest == null)
            {
                throw new InvalidLeagueRequest("The league request object cannot be null.");
            }

            if (String.IsNullOrEmpty(leagueRequest.LeagueName))
            {
                throw new InvalidLeagueRequest("The league name cannot be empty.");
            }

            if (leagueRequest.Owner == null)
            {
                throw new InvalidLeagueRequest("The league owner cannot be null.");
            }

            if (BaseRepositoryImpl.CreateInstance().GetUserByField("Id", leagueRequest.Owner.Id) == null)
            {
                throw new InvalidLeagueRequest("The league owner specified does not exist.");
            }
        }
    }
}
